package com.mrx.spring.security.filter;

import com.mrx.spring.security.exception.SecurityException;
import com.mrx.spring.security.model.ApiPermission;
import com.mrx.spring.security.service.ISecurityService;
import com.mrx.spring.security.utils.SecurityUtils;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Objects;
import java.util.Set;

/**
 * 用户接口权限 校验过滤器
 *
 * @author Mr.X
 * @since 2024-02-24 上午 11:22:22
 **/
@Order(1)
@Component
public class ApiPermissionFilter extends OncePerRequestFilter {

    @Resource
    private ISecurityService securityService;

    private static final AntPathMatcher antPathMatcher = new AntPathMatcher();

    private static final Logger logger = LoggerFactory.getLogger(ApiPermissionFilter.class);

    @PostConstruct
    public void init() {
        logger.info("Using {} to Secure Api Permission", getClass());
    }

    @Override
    protected void doFilterInternal(
            @NotNull HttpServletRequest request, @NonNull HttpServletResponse response, @NotNull FilterChain filterChain
    ) throws ServletException, IOException {
        String url = request.getRequestURI();
        boolean needSecure = securityService.permitUrls().stream().noneMatch(it -> antPathMatcher.match(it, url));
        if (securityService.enableApiPermission() && needSecure) {
            logger.info("启用 api 权限校验");
            Set<ApiPermission> permissions = Objects.requireNonNull(SecurityUtils.getCurrentUser()).getPermissions();
            if (permissions.stream().anyMatch(it -> antPathMatcher.match(it.getPath(), url))) {
                filterChain.doFilter(request, response);
            } else {
                throw new SecurityException("unauthorized");
            }
        } else {
            filterChain.doFilter(request, response);
        }
    }

}
